"""用户认证模块的序列化器

定义用户认证相关的数据序列化器，用于API数据的序列化和反序列化。
"""

from rest_framework import serializers
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from django.contrib.auth import authenticate
from django.contrib.auth.password_validation import validate_password
from django.core.exceptions import ValidationError
from .models import User, UserProfile, LoginHistory


class UserRegistrationSerializer(serializers.ModelSerializer):
    """用户注册序列化器
    
    处理用户注册时的数据验证和序列化。
    """
    
    password = serializers.CharField(
        write_only=True,
        min_length=8,
        style={'input_type': 'password'},
        help_text='密码长度至少8位'
    )
    
    password_confirm = serializers.CharField(
        write_only=True,
        style={'input_type': 'password'},
        help_text='确认密码'
    )
    
    class Meta:
        model = User
        fields = [
            'username', 'email', 'password', 'password_confirm',
            'first_name', 'last_name', 'bio'
        ]
        extra_kwargs = {
            'email': {'required': True},
            'username': {'required': True},
        }
    
    def validate_email(self, value):
        """验证邮箱地址唯一性"""
        if User.objects.filter(email=value).exists():
            raise serializers.ValidationError('该邮箱地址已被注册')
        return value
    
    def validate_username(self, value):
        """验证用户名唯一性"""
        if User.objects.filter(username=value).exists():
            raise serializers.ValidationError('该用户名已被使用')
        return value
    
    def validate(self, attrs):
        """验证密码一致性和强度"""
        password = attrs.get('password')
        password_confirm = attrs.pop('password_confirm', None)
        
        if password != password_confirm:
            raise serializers.ValidationError({
                'password_confirm': '两次输入的密码不一致'
            })
        
        # 验证密码强度
        try:
            validate_password(password)
        except ValidationError as e:
            raise serializers.ValidationError({
                'password': list(e.messages)
            })
        
        return attrs
    
    def create(self, validated_data):
        """创建新用户"""
        password = validated_data.pop('password')
        user = User.objects.create_user(
            password=password,
            **validated_data
        )
        
        # 创建用户配置
        UserProfile.objects.create(user=user)
        
        return user


class CustomTokenObtainPairSerializer(TokenObtainPairSerializer):
    """自定义JWT Token获取序列化器
    
    扩展默认的Token序列化器，添加用户信息。
    """
    
    username_field = 'email'  # 使用邮箱作为登录字段
    
    def validate(self, attrs):
        """验证登录凭据并记录登录历史"""
        email = attrs.get('email')
        password = attrs.get('password')
        
        if email and password:
            user = authenticate(
                request=self.context.get('request'),
                username=email,
                password=password
            )
            
            if not user:
                # 记录登录失败
                self._record_login_attempt(email, False, '用户名或密码错误')
                raise serializers.ValidationError(
                    '用户名或密码错误',
                    code='authorization'
                )
            
            if not user.is_active:
                self._record_login_attempt(email, False, '账户已被禁用')
                raise serializers.ValidationError(
                    '账户已被禁用',
                    code='authorization'
                )
            
            # 记录登录成功
            self._record_login_attempt(email, True)
            
        else:
            raise serializers.ValidationError(
                '必须提供邮箱和密码',
                code='authorization'
            )
        
        data = super().validate(attrs)
        
        # 添加用户信息到token响应
        data['user'] = UserSerializer(user).data
        
        return data
    
    def _record_login_attempt(self, email, success, failure_reason=''):
        """记录登录尝试"""
        try:
            user = User.objects.get(email=email) if success else None
        except User.DoesNotExist:
            user = None
        
        request = self.context.get('request')
        if request and user:  # 只有在用户存在时才记录登录历史
            LoginHistory.objects.create(
                user=user,
                ip_address=self._get_client_ip(request),
                user_agent=request.META.get('HTTP_USER_AGENT', ''),
                is_successful=success,
                failure_reason=failure_reason
            )
    
    def _get_client_ip(self, request):
        """获取客户端IP地址"""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip


class UserSerializer(serializers.ModelSerializer):
    """用户信息序列化器
    
    用于序列化用户基本信息。
    """
    
    full_name = serializers.CharField(source='get_full_name', read_only=True)
    avatar_url = serializers.SerializerMethodField()
    
    class Meta:
        model = User
        fields = [
            'id', 'username', 'email', 'first_name', 'last_name',
            'full_name', 'bio', 'avatar', 'avatar_url',
            'theme_preference', 'language_preference',
            'email_notifications', 'is_email_verified',
            'last_activity', 'created_at'
        ]
        read_only_fields = [
            'id', 'is_email_verified', 'last_activity', 'created_at'
        ]
    
    def get_avatar_url(self, obj):
        """获取头像URL"""
        if obj.avatar:
            request = self.context.get('request')
            if request:
                return request.build_absolute_uri(obj.avatar.url)
            return obj.avatar.url
        return None


class UserProfileSerializer(serializers.ModelSerializer):
    """用户配置序列化器
    
    用于序列化用户的详细配置信息。
    """
    
    class Meta:
        model = UserProfile
        fields = [
            'editor_theme', 'editor_font_size', 'editor_font_family',
            'auto_save_enabled', 'auto_save_interval',
            'sync_enabled', 'updated_at'
        ]
        read_only_fields = ['updated_at']


class UserUpdateSerializer(serializers.ModelSerializer):
    """用户信息更新序列化器
    
    用于更新用户基本信息。
    """
    
    class Meta:
        model = User
        fields = [
            'first_name', 'last_name', 'bio',
            'theme_preference', 'language_preference',
            'email_notifications'
        ]
    
    def update(self, instance, validated_data):
        """更新用户信息"""
        for attr, value in validated_data.items():
            setattr(instance, attr, value)
        instance.save()
        return instance


class PasswordChangeSerializer(serializers.Serializer):
    """密码修改序列化器
    
    处理用户密码修改。
    """
    
    old_password = serializers.CharField(
        write_only=True,
        style={'input_type': 'password'},
        help_text='当前密码'
    )
    
    new_password = serializers.CharField(
        write_only=True,
        min_length=8,
        style={'input_type': 'password'},
        help_text='新密码，长度至少8位'
    )
    
    new_password_confirm = serializers.CharField(
        write_only=True,
        style={'input_type': 'password'},
        help_text='确认新密码'
    )
    
    def validate_old_password(self, value):
        """验证当前密码"""
        user = self.context['request'].user
        if not user.check_password(value):
            raise serializers.ValidationError('当前密码不正确')
        return value
    
    def validate(self, attrs):
        """验证新密码"""
        new_password = attrs.get('new_password')
        new_password_confirm = attrs.get('new_password_confirm')
        
        if new_password != new_password_confirm:
            raise serializers.ValidationError({
                'new_password_confirm': '两次输入的新密码不一致'
            })
        
        # 验证密码强度
        try:
            validate_password(new_password)
        except ValidationError as e:
            raise serializers.ValidationError({
                'new_password': list(e.messages)
            })
        
        return attrs
    
    def save(self):
        """保存新密码"""
        user = self.context['request'].user
        user.set_password(self.validated_data['new_password'])
        user.save()
        return user


class LoginHistorySerializer(serializers.ModelSerializer):
    """登录历史序列化器
    
    用于序列化用户登录历史记录。
    """
    
    session_duration_minutes = serializers.SerializerMethodField()
    
    class Meta:
        model = LoginHistory
        fields = [
            'id', 'ip_address', 'user_agent', 'is_successful',
            'failure_reason', 'login_time', 'logout_time',
            'session_duration_minutes'
        ]
        read_only_fields = ['id', 'login_time']
    
    def get_session_duration_minutes(self, obj):
        """获取会话持续时间（分钟）"""
        duration = obj.session_duration
        if duration:
            return int(duration.total_seconds() / 60)
        return None